# -*- coding: utf-8 -*-
"""
Created on Mon Nov 18 13:00:38 2013

@author: wudong

File location :
D:\CodeProject\MyCodeLib\MyPythonLib

usage :
import numpy as np
import abaHelper as ah

Reload the updated module :
import abaHelper as ah
reload(ah)

"""
import numpy as np
import os
#
# ============================================================================
#
# short for textRepr.prettyPrint
def pp(obj):
    from textRepr import prettyPrint
    prettyPrint(obj)
    pass
#
# ============================================================================
#
# read data from text data file
def loadtxt(fname, delimiter=',', comments='#', converters=None,
            skiprows=0, usecols=None, unpack=False):
    X = np.loadtxt(fname, np.dtype(np.float), comments, delimiter,
        converters, skiprows, usecols, unpack)
    return X
#
# ============================================================================
#
# save numpy array X to text file
def savetxt(fname, X, fmt='%.6e', delimiter=', '):
    np.savetxt(fname, X, fmt=fmt, delimiter=delimiter)
    pass
#
# ============================================================================
#
# convert a 2D numpy array to abaqus table
#   abaqus table:
#       ((1,2), (3,4), (5,6))
def arrayToTable(arrayData):
    table = []
    (row,col) = arrayData.shape
    for i in range(row):
        rowData = []
        for j in range(col):
            rowData.append(arrayData[i,j])
            pass
        table.append(tuple(rowData))
    return tuple(table)
#
# ============================================================================
#
# Convert an abaqus table to 2D numpy array
def tableToArray(table):
    row = len(table)
    col = len(table[0])
    arrayData = np.zeros(shape=(row,col))
    for i in range(row):
        for j in range(col):
            arrayData[i,j] = table[i][j]
    return arrayData
#
# ============================================================================
#
def loadArray(fname, delimiter=','):
    arrayData = np.loadtxt(fname, delimiter=delimiter)
    return arrayData
#
# ============================================================================
#
def loadTable(fname, delimiter=','):
    arrayData = loadArray(fname, delimiter=delimiter)
    table = arrayToTable(arrayData)
    return table
#
# ============================================================================
#
def saveArray(fname, X, fmt='%13.6e', delimiter=','):
    np.savetxt(fname, X, fmt=fmt, delimiter=delimiter)
#
# ============================================================================
#
def isSamePath(path1, path2):
    return os.path.normpath(path1)==os.path.normpath(path2)
#
# ============================================================================
#
def openOdb(odbPath):
    from abaqus import session
    import odbAccess
    myOdb = None
    absOdbPath = os.path.abspath(odbPath)
    for path in session.odbs.keys():
        if isSamePath(absOdbPath,path):
            myOdb = session.odbs[path]
    if myOdb==None:
        myOdb = odbAccess.openOdb(path=absOdbPath)
    return myOdb
#
# ============================================================================
#
def getOdbNodeSets(odb):
    instance = odb.rootAssembly.instances.values()[0]
    return instance.nodeSets
#
# ============================================================================
#
def getOdbElemSets(odb):
    instance = odb.rootAssembly.instances.values()[0]
    return instance.elementSets

def getFrameFieldOutputs(frame,varName,region):
    # frame = step.frames[frameNum]
    return frame.fieldOutputs[varName].getSubset(region=region)
#
# ============================================================================
#
def getOdbFieldOutputs(step,outputVarNames,region):
    elemCount = len(region.elements)
    frameCount = len(step.frames)
    varCount = len(outputVarNames)
    elemLabels = np.zeros(shape=(elemCount,varCount))
    frameInfo = np.zeros(shape=(frameCount,2))
    outputData = np.zeros(shape=(elemCount,frameCount,varCount))
    for j in range(frameCount):
    	frame = step.frames[j]
    	frameNum = frame.incrementNumber
    	frameTime = frame.frameValue
    	frameInfo[j,0] = frameNum
    	frameInfo[j,1] = frameTime
    	for k in range(varCount):
    		varName = outputVarNames[k]
    		varData = getFrameFieldOutputs(frame,varName,region)
    		for i in range(elemCount):
    			v = varData.values[i]
    			elemLabels[i,k] = v.elementLabel
    			outputData[i,j,k] = v.data
    return (elemLabels,frameInfo,outputData)
#
# ============================================================================
#
def getOdbNodeLabel(odb,nodeSetName):
    instance = odb.rootAssembly.instances.values()[0]
    nodeLabel = instance.nodeSets[nodeSetName].nodes[0].label
    return nodeLabel
#
# ============================================================================
#
def getOdbNodeHistData(odb,stepName,nodeSetName,varName):
    instance = odb.rootAssembly.instances.values()[0]
    nodeLabel = instance.nodeSets[nodeSetName].nodes[0].label
    histName = 'Node %s.%d' % (instance.name,nodeLabel)
    step = odb.steps[stepName]
    histRegion = step.historyRegions[histName]
    histData = histRegion.historyOutputs[varName].data
    histData = tableToArray(histData)
    return histData
#
# ============================================================================
#
def getModelNodeLabel(model,nodeSetName):
	instance = model.rootAssembly.instances.values()[0]
	nodeLabel = instance.sets[nodeSetName].nodes[0].label
	return nodeLabel
#
# ============================================================================
#
def getModelBlockPosition(model, blockPrefix):
    if blockPrefix == '':
        return len(model.keywordBlock.sieBlocks)-1
    pos = 0
    for block in model.keywordBlock.sieBlocks:
        if block[0:len(blockPrefix)].lower()==blockPrefix.lower():
            return pos
        pos=pos+1
    return -1
#
# ============================================================================
#
def setSpringDashpot(model,portionName,nodeLabel,dof,
		spBehavior,spCoef, dpBehavior,dpCoef):
	import regionToolset
	instance = model.rootAssembly.instances.values()[0]
	modelNodes = instance.nodes
	nodeRegion = modelNodes.sequenceFromLabels((nodeLabel,))
	region=regionToolset.Region(nodes=nodeRegion)
	sprDashpotName = 'sd_%s_%d_%d' % (portionName,nodeLabel,dof)
	model.rootAssembly.engineeringFeatures.SpringDashpotToGround(
		name=sprDashpotName, region=region, orientation=None, dof=dof, 
		springBehavior=spBehavior, springStiffness=spCoef, 
		dashpotBehavior=dpBehavior, dashpotCoefficient=dpCoef )
#
# ============================================================================
#
def applyConcentratedForce(model,stepName,portionName,nodeLabel,
		dof,ampData,amp=1.0):
	from abaqusConstants import STEP,SOLVER_DEFAULT,UNIFORM
	import regionToolset
	instance = model.rootAssembly.instances.values()[0]
	modelNodes = instance.nodes
	nodeRegion = modelNodes.sequenceFromLabels((nodeLabel,))
	region=regionToolset.Region(nodes=nodeRegion)
	#
	ampName = 'Amp_%s_%d_%d' % (portionName,nodeLabel,dof)
	ampDataTable = arrayToTable(ampData)
	model.TabularAmplitude(name=ampName, timeSpan=STEP, 
		smooth=SOLVER_DEFAULT, data=ampDataTable)
	#
	loadName = 'CF_%s_%d_%d' % (portionName,nodeLabel,dof)
	cfs = [0,0,0]
	cfs[dof-1] = amp
	model.ConcentratedForce(name=loadName, createStepName=stepName,
		region=region, cf1=cfs[0], cf2=cfs[1], cf3=cfs[2], amplitude=ampName, 
		distributionType=UNIFORM, field='', localCsys=None)
#
# ============================================================================
#
